package clubhouse.communication;

import java.util.Vector;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

import clubhouse.motioncommand.MotionCommand;
import clubhouse.motioncommand.NodeControl;

/**
 * @author Anis Darwich & Lionel Croix - Simulation and experimentation on Robot in WSN - WnSN Lab - SJTU
 */
public class ReceptionFifo {
	
	/**Object used to display logs in message log panel.*/
	private final static Logger log = Logger.getLogger(ReceptionFifo.class);
	
	/**Queue vector of motion Ack message.*/
	private Vector<MotionCommand> motionAck;
	/**Queue vector of nodes message.*/
	private Vector<NodeControl> nodeMeasurement;
	
	/**
	 * Constructs the ReceptionFifo object. Instantiate its two queue vectors, one for node data and the other for received acks.
	 */
	public ReceptionFifo() {
		PropertyConfigurator.configure("log4j.properties");
		this.motionAck = new Vector<MotionCommand>(100,10);
		this.nodeMeasurement = new Vector<NodeControl>(100,10);
	}
	
	/**
	 * Return the lock used for all synchronization for this object.
	 * @return the value of the lock, true if the object is free, false if it used.
	 */
	protected Object getLock() {
		return this;
	}
	
	/**
	 * Add the specified NodeControl message to the reception fifo queue.
	 * @param msg the message to add in the node data queue.
	 */
	public void rxNodeMeasurement(NodeControl msg) {
		synchronized(this.getLock()) {
			this.nodeMeasurement.add(msg);
			log.debug("Added "+ msg.toHexPrint() + " to nodeMeasurement\n");
		}
	}
	
	/**
	 * Add the specified MotionCommand message of type ACK to the reception fifo queue.
	 * @param msg the Ack message to add in the ack message queue.
	 */
	public void rxMotionAck(MotionCommand msg) {
		synchronized(this.getLock()) {
			this.motionAck.add(msg);
			log.debug("Added "+ msg.toHexPrint() + " to motionAck\n");
		}
	}
	
	/**
	 * Get the first element in the NodeControl reception fifo queue.
	 * @return the first element of the node data reception queue, null if the queue is empty.
	 */
	public NodeControl getNodeMeasurement() {
		if (this.nodeMeasurement.size() != 0) {
			NodeControl tmp = this.nodeMeasurement.firstElement();
			this.nodeMeasurement.remove(0);
			log.debug("Retrieved "+ tmp.toHexPrint() + " from nodeMeasurement\n");
			return tmp;
		} else {
			return null;
		}
	}
	
	/**
	 * Get the number of NodeControl messages available in the NodeControl reception fifo queue.
	 * @return the size of the current data reception queue vector.
	 */
	public int nodeMeasurementAvailable() {
		return this.nodeMeasurement.size();
	}
	
	/**
	 * Get the first element in the MotionCommand reception fifo queue.
	 * @return the first element of the Ack reception queue, null if the queue is empty.
	 */
	public MotionCommand getMotionAck() {
		synchronized(this.getLock()) {
			if (this.motionAck.size() != 0) {
				MotionCommand tmp = this.motionAck.firstElement();
				this.motionAck.remove(0);
				log.debug("Retrieved "+ tmp.toHexPrint() + " from motionAck\n");
				return tmp;
			} else {
				return null;
			}
		}
	}
	
	/**
	 * Get the number of MotionCommand messages available in the MotionCommand reception fifo queue.
	 * @return the size of the current data reception queue vector.
	 */
	public int motionAckAvailable() {
		return this.motionAck.size();
	}
	
	/**
	 * Return a vector with the received NodeControl messages.
	 * @return a vector containing all node data messages received.
	 */
	public Vector<double[]> getReceivedLandmarks() {
		synchronized(this.getLock()) {
			Vector<double[]> tmp = new Vector<double[]>(10,1);
			NodeControl tmpMsg;
			while ((tmpMsg = getNodeMeasurement()) != null) {
				tmp.add(new double[] {(double)tmpMsg.getSource(), (double)tmpMsg.getX(), (double)tmpMsg.getY()});
			}
			return tmp;
		}
	}
}
